﻿
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;


[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
    Format.UserDefined,
    IsInvariantToDuplicates = false,
    IsInvariantToNulls = false,
    IsInvariantToOrder = false,
    MaxByteSize = -1)]
public struct RangeAgg : IBinarySerialize
{
    //List of values for range calculation;
    private List<double> rl;

    
    // Initialize variables
    public void Init()
    {
        rl = new List<double>();
    }


    // Accumulate row values
    public void Accumulate(SqlDouble rec_value)
    {
        if (!rec_value.IsNull)
        {
            rl.Add(rec_value.Value);
        }
    }


    // Merge the partially computed aggregates with this aggregate.
    // The other partial results to be merged
    public void Merge(RangeAgg Group)
    {
        this.rl.AddRange(Group.rl.ToArray());
    }

    // Called at the end of aggregation, to return the results.
    // The RangeAgg of all inputted values
    public SqlDouble Terminate()
    {
        //debug: return (SqlDouble)ld.Count;

        //special case 0 values
        if (rl.Count == 0)
            return SqlDouble.Null;

        rl.Sort();
        return (SqlDouble)(rl[rl.Count -1] - rl[0]);
    }


    #region IBinarySerialize Members

    public void Read(System.IO.BinaryReader r)
    {
        int cnt = r.ReadInt32();
        this.rl = new List<double>(cnt);
        for (int i = 0; i < cnt; i++)
        {
            this.rl.Add(r.ReadDouble());
        }
    }

    public void Write(System.IO.BinaryWriter w)
    {
        w.Write(this.rl.Count);
        foreach (double d in this.rl)
        {
            w.Write(d);
        }
    }

    #endregion
}